#include "doorbell_lcd.h"
#include <string.h>
#include "doorbell_config.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_dev.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_heap_caps.h"

static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;
static uint8_t *s_lcd_cache[2] = {0};

void doorbell_lcd_init(void)
{
    // 1. 初始化背光引脚
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << LCD_BG_PIN};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
    // 关闭背光
    gpio_set_level(LCD_BG_PIN, 0);

    // 2. 初始化SPI总线
    spi_bus_config_t buscfg = {
        .sclk_io_num = LCD_CLK_PIN,
        .mosi_io_num = LCD_MOSI_PIN,
        .miso_io_num = LCD_MISO_PIN,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));

    // 3. 初始化io_handle
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = LCD_DC_PIN,
        .cs_gpio_num = LCD_CS_PIN,
        .pclk_hz = 40 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI2_HOST, &io_config, &io_handle));

    // 4. 初始化LCD句柄
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = LCD_RST_PIN,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

    // 5. 显示初始化
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, false));
    // 反色
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
    // 改成横屏
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));

    // 申请显示缓存
    s_lcd_cache[0] = heap_caps_malloc(LCD_WIDTH * 2, MALLOC_CAP_DMA);
    s_lcd_cache[1] = heap_caps_malloc(LCD_WIDTH * 2, MALLOC_CAP_DMA);
}

void doorbell_lcd_deinit(void)
{
    doorbell_lcd_off();
    esp_lcd_panel_del(panel_handle);
    esp_lcd_panel_io_del(io_handle);
    spi_bus_free(SPI2_HOST);

    free(s_lcd_cache[0]);
    free(s_lcd_cache[1]);
}

void doorbell_lcd_on(void)
{
    esp_lcd_panel_disp_on_off(panel_handle, true);
    gpio_set_level(LCD_BG_PIN, 1);
}

void doorbell_lcd_off(void)
{
    gpio_set_level(LCD_BG_PIN, 0);
    esp_lcd_panel_disp_on_off(panel_handle, false);
}

void doorbell_lcd_show_image(const void *image)
{
    int current_line = 0;
    for (size_t i = 0; i < LCD_HEIGHT; i++)
    {
        memcpy(s_lcd_cache[current_line], image + i * LCD_WIDTH * 2, LCD_WIDTH * 2);
        esp_lcd_panel_draw_bitmap(panel_handle, 0, i, LCD_WIDTH, i + 1, s_lcd_cache[current_line]);
        current_line = 1 - current_line;
    }
}
